/*
 * Copyright (C) 1997-2001 Id Software, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * =======================================================================
 *
 * Global string matching
 *
 * =======================================================================
 */ 

#include <stdio.h>
#include "header/glob.h"

/* 
 * Like glob_match, but match PATTERN against any final segment of TEXT.  
 */
static int
glob_match_after_star ( char *pattern, char *text )
{
	register char *p = pattern, *t = text;
	register char c, c1;

	while ( ( c = *p++ ) == '?' || c == '*' )
	{
		if ( ( c == '?' ) && ( *t++ == '\0' ) )
		{
			return ( 0 );
		}
	}

	if ( c == '\0' )
	{
		return ( 1 );
	}

	if ( c == '\\' )
	{
		c1 = *p;
	}
	else
	{
		c1 = c;
	}

	while ( 1 )
	{
		if ( ( ( c == '[' ) || ( *t == c1 ) ) && glob_match( p - 1, t ) )
		{
			return ( 1 );
		}

		if ( *t++ == '\0' )
		{
			return ( 0 );
		}
	}
}

/* Match the pattern PATTERN against the string TEXT;
 * return 1 if it matches, 0 otherwise.
 *
 * A match means the entire string TEXT is used up in matching.
 *
 * In the pattern string, `*' matches any sequence of characters,
 * `?' matches any character, [SET] matches any character in the specified set,
 * [!SET] matches any character not in the specified set.
 *
 * A set is composed of characters or ranges; a range looks like
 * character hyphen character (as in 0-9 or A-Z).
 * [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
 * Any other character in the pattern must be matched exactly.
 *
 * To suppress the special syntactic significance of any of `[]*?!-\',
 * and match the character exactly, precede it with a `\'.
 */
int
glob_match ( char *pattern, char *text )
{
	register char *p = pattern, *t = text;
	register char c;

	while ( ( c = *p++ ) != '\0' )
	{
		switch ( c )
		{
			case '?':

				if ( *t == '\0' )
				{
					return ( 0 );
				}
				else
				{
					++t;
				}

				break;

			case '\\':

				if ( *p++ != *t++ )
				{
					return ( 0 );
				}

				break;

			case '*':
				return ( glob_match_after_star( p, t ) );

			case '[':
			{
				register char c1 = *t++;
				int invert;

				if ( !c1 )
				{
					return ( 0 );
				}

				invert = ( ( *p == '!' ) || ( *p == '^' ) );

				if ( invert )
				{
					p++;
				}

				c = *p++;

				while ( 1 )
				{
					register char cstart = c, cend = c;

					if ( c == '\\' )
					{
						cstart = *p++;
						cend = cstart;
					}

					if ( c == '\0' )
					{
						return ( 0 );
					}

					c = *p++;

					if ( ( c == '-' ) && ( *p != ']' ) )
					{
						cend = *p++;

						if ( cend == '\\' )
						{
							cend = *p++;
						}

						if ( cend == '\0' )
						{
							return ( 0 );
						}

						c = *p++;
					}

					if ( ( c1 >= cstart ) && ( c1 <= cend ) )
					{
						goto match;
					}

					if ( c == ']' )
					{
						break;
					}
				}

				if ( !invert )
				{
					return ( 0 );
				}

				break;

			match:

				/* Skip the rest of the [...] construct that already matched.  */
				while ( c != ']' )
				{
					if ( c == '\0' )
					{
						return ( 0 );
					}

					c = *p++;

					if ( c == '\0' )
					{
						return ( 0 );
					}
					else if ( c == '\\' )
					{
						++p;
					}
				}

				if ( invert )
				{
					return ( 0 );
				}

				break;
			}

			default:

				if ( c != *t++ )
				{
					return ( 0 );
				}
		}
	}

	return ( *t == '\0' );
}

